home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / epsilon / expose.py < prev    next >
Text File  |  2009-03-13  |  4KB  |  142 lines

  1. # Copright 2008 Divmod, Inc.  See LICENSE file for details.
  2. # -*- test-case-name: epsilon.test.test_expose -*-
  3.  
  4. """
  5. This module provides L{Exposer}, a utility for creating decorators that expose
  6. methods on types for a particular purpose.
  7.  
  8. The typical usage of this module is for an infrastructure layer (usually one
  9. that allows methods to be invoked from the network, directly or indirectly) to
  10. provide an explicit API for exposing those methods securely.
  11.  
  12. For example, a sketch of a finger protocol implementation which could use this
  13. to expose the results of certain methods as finger results::
  14.  
  15.     # tx_finger.py
  16.     fingermethod = Exposer("This object exposes finger methods.")
  17.     ...
  18.     class FingerProtocol(Protocol):
  19.         def __init__(self, fingerModel):
  20.             self.model = fingerModel
  21.         ...
  22.         def fingerQuestionReceived(self, whichUser):
  23.             try:
  24.                 method = fingermethod.get(self.model, whichUser)
  25.             except MethodNotExposed:
  26.                 method = lambda : "Unknown user"
  27.             return method()
  28.  
  29.     # myfingerserver.py
  30.     from tx_finger import fingermethod
  31.     ...
  32.     class MyFingerModel(object):
  33.         @fingermethod.expose("bob")
  34.         def someMethod(self):
  35.             return "Bob is great."
  36.  
  37. Assuming lots of protocol code to hook everything together, this would then
  38. allow you to use MyFingerModel and 'finger bob' to get the message 'Bob is
  39. great.'
  40. """
  41.  
  42. import inspect
  43.  
  44. from types import FunctionType
  45.  
  46.  
  47. class MethodNotExposed(Exception):
  48.     """
  49.     The requested method was not exposed for the purpose requested.  More
  50.     specifically, L{Exposer.get} was used to retrieve a key from an object
  51.     which does not expose that key with that exposer.
  52.     """
  53.  
  54.  
  55. class NameRequired(Exception):
  56.     """
  57.     L{Exposer.expose} was used to decorate a non-function object without having
  58.     a key explicitly specified.
  59.     """
  60.  
  61.  
  62.  
  63. class Exposer(object):
  64.     """
  65.     This is an object that can expose and retrieve methods on classes.
  66.  
  67.     @ivar _exposed: a dict mapping exposed keys to exposed function objects.
  68.     """
  69.  
  70.     def __init__(self, doc):
  71.         """
  72.         Create an exposer.
  73.         """
  74.         self.__doc__ = doc
  75.         self._exposed = {}
  76.  
  77.  
  78.     def expose(self, key=None):
  79.         """
  80.         Expose the decorated method for this L{Exposer} with the given key.  A
  81.         method which is exposed will be able to be retrieved by this
  82.         L{Exposer}'s C{get} method with that key.  If no key is provided, the
  83.         key is the method name of the exposed method.
  84.  
  85.         Use like so::
  86.  
  87.             class MyClass:
  88.                 @someExposer.expose()
  89.                 def foo(): ...
  90.  
  91.         or::
  92.  
  93.             class MyClass:
  94.                 @someExposer.expose('foo')
  95.                 def unrelatedMethodName(): ...
  96.  
  97.         @param key: a hashable object, used by L{Exposer.get} to look up the
  98.         decorated method later.  If None, the key is the exposed method's name.
  99.  
  100.         @return: a 1-argument callable which records its input as exposed, then
  101.         returns it.
  102.         """
  103.         def decorator(function):
  104.             rkey = key
  105.             if rkey is None:
  106.                 if isinstance(function, FunctionType):
  107.                     rkey = function.__name__
  108.                 else:
  109.                     raise NameRequired()
  110.             if rkey not in self._exposed:
  111.                 self._exposed[rkey] = []
  112.             self._exposed[rkey].append(function)
  113.             return function
  114.         return decorator
  115.  
  116.  
  117.     def get(self, obj, key):
  118.         """
  119.         Retrieve 'key' from an instance of a class which previously exposed it.
  120.  
  121.         @param key: a hashable object, previously passed to L{Exposer.expose}.
  122.  
  123.         @return: the object which was exposed with the given name on obj's key.
  124.  
  125.         @raise MethodNotExposed: when the key in question was not exposed with
  126.         this exposer.
  127.         """
  128.         if key not in self._exposed:
  129.             raise MethodNotExposed()
  130.         rightFuncs = self._exposed[key]
  131.         T = obj.__class__
  132.         seen = {}
  133.         for subT in inspect.getmro(T):
  134.             for name, value in subT.__dict__.items():
  135.                 for rightFunc in rightFuncs:
  136.                     if value is rightFunc:
  137.                         if name in seen:
  138.                             raise MethodNotExposed()
  139.                         return value.__get__(obj, T)
  140.                 seen[name] = True
  141.         raise MethodNotExposed()
  142.